/**
 * 请求工具函数
 */

import { apiClient } from './instance'
import type { ApiResponse, RequestOptions, PaginatedResponse } from '@/types/api'

/** 快速GET请求 */
export const get = <T = any>(
  url: string,
  params?: Record<string, any>,
  options?: RequestOptions
): Promise<ApiResponse<T>> => {
  const searchParams = params ? new URLSearchParams(params) : undefined
  return apiClient.get<T>(url, {
    ...options,
    searchParams,
  })
}

/** 快速POST请求 */
export const post = <T = any>(
  url: string,
  data?: any,
  options?: RequestOptions
): Promise<ApiResponse<T>> => {
  return apiClient.post<T>(url, data, options)
}

/** 快速PUT请求 */
export const put = <T = any>(
  url: string,
  data?: any,
  options?: RequestOptions
): Promise<ApiResponse<T>> => {
  return apiClient.put<T>(url, data, options)
}

/** 快速DELETE请求 */
export const del = <T = any>(
  url: string,
  options?: RequestOptions
): Promise<ApiResponse<T>> => {
  return apiClient.delete<T>(url, options)
}

/** 分页请求 */
export const getPaginated = <T = any>(
  url: string,
  params: {
    page?: number
    pageSize?: number
    [key: string]: any
  } = {},
  options?: RequestOptions
): Promise<ApiResponse<PaginatedResponse<T>>> => {
  const { page = 1, pageSize = 10, ...otherParams } = params
  return get<PaginatedResponse<T>>(url, {
    page,
    pageSize,
    ...otherParams,
  }, options)
}

/** 上传文件 */
export const upload = <T = any>(
  url: string,
  file: File,
  options?: RequestOptions & {
    onProgress?: (progress: number) => void
  }
): Promise<ApiResponse<T>> => {
  return apiClient.upload<T>(url, file, options)
}

/** 批量上传文件 */
export const uploadMultiple = <T = any>(
  url: string,
  files: File[],
  options?: RequestOptions
): Promise<ApiResponse<T>> => {
  const formData = new FormData()
  files.forEach((file, index) => {
    formData.append(`files[${index}]`, file)
  })
  return apiClient.upload<T>(url, formData, options)
}

/** 下载文件 */
export const download = async (
  url: string,
  filename?: string,
  options?: RequestOptions
): Promise<void> => {
  try {
    const response = await apiClient.get(url, {
      ...options,
      // 不解析为JSON，直接获取blob
    } as any)

    // 这里需要直接使用ky实例来获取blob
    const blob = await (response as any).blob()

    // 创建下载链接
    const downloadUrl = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = filename || 'download'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(downloadUrl)
  } catch (error) {
    console.error('下载文件失败:', error)
    throw error
  }
}

/** 请求重试包装器 */
export const withRetry = <T extends (...args: any[]) => Promise<any>>(
  fn: T,
  maxRetries: number = 3,
  delay: number = 1000
): T => {
  return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
    let lastError: Error

    for (let i = 0; i <= maxRetries; i++) {
      try {
        return await fn(...args)
      } catch (error) {
        lastError = error as Error

        if (i === maxRetries) {
          throw lastError
        }

        // 等待后重试
        await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i)))
      }
    }

    throw lastError!
  }) as T
}

/** 并发请求控制 */
export const concurrent = async <T>(
  requests: (() => Promise<T>)[],
  limit: number = 3
): Promise<T[]> => {
  const results: T[] = []
  const executing: Promise<void>[] = []

  for (const request of requests) {
    const promise = request().then(result => {
      results.push(result)
    })

    executing.push(promise)

    if (executing.length >= limit) {
      await Promise.race(executing)
      executing.splice(executing.findIndex(p => p === promise), 1)
    }
  }

  await Promise.all(executing)
  return results
}

/** 请求缓存装饰器 */
const requestCache = new Map<string, { data: any; timestamp: number }>()

export const withCache = <T extends (...args: any[]) => Promise<any>>(
  fn: T,
  ttl: number = 5 * 60 * 1000 // 默认5分钟缓存
): T => {
  return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
    const cacheKey = JSON.stringify(args)
    const cached = requestCache.get(cacheKey)

    if (cached && Date.now() - cached.timestamp < ttl) {
      return cached.data
    }

    const result = await fn(...args)
    requestCache.set(cacheKey, {
      data: result,
      timestamp: Date.now()
    })

    return result
  }) as T
}

/** 清除请求缓存 */
export const clearCache = (pattern?: string): void => {
  if (pattern) {
    for (const key of requestCache.keys()) {
      if (key.includes(pattern)) {
        requestCache.delete(key)
      }
    }
  } else {
    requestCache.clear()
  }
}
